from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from core.agent.examModel import ExamGenerator
from core.agent.abstractModel import AbstractModel
from utils.auth import get_current_user
from models.models import LearnUser
from crud.page_record import get_all_knowledge_points_by_date_range, get_today_knowledge_points
from crud.material import get_material_content
from schemas.material import MaterialContent
from sqlalchemy.orm import Session
from database import SessionLocal
from utils.log_manager import app_logger
from utils.utils import deduplicate_dict_list
import math
import random
from config import settings

router = APIRouter(prefix="/agent")
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

api_key = settings.api_key
api_base = settings.api_base


# 创建分析器实例，设置默认难度为"normal"
exam = ExamGenerator(api_key, api_base,model_name=settings.api_generate_model)
abstract = AbstractModel(api_key, api_base,model_name=settings.api_abstract_model)


# 定义请求体模型

class ExamRequest(BaseModel):
    text: str
    material_id: int = None
    num_questions: int
    question_types: str
    difficulty: str



@router.post("/getToDayExam")
async def get_to_day_exam(req: ExamRequest, db: Session = Depends(get_db),current_user: LearnUser = Depends(get_current_user)):
    try:
        if req.num_questions > 30:
            app_logger.info(f"今日测验的题目数量大于30！！！")
            raise HTTPException(status_code=400, detail=str("今日测验的题目数量大于30"))
        # 获取当日的所有知识点
        knowledge_points = get_today_knowledge_points(db, current_user.id)
        today_materials = [{"material_id":point.material_id,"page_number":point.page_number} for point in knowledge_points]
        
        # 去重 today_materials
        today_materials = deduplicate_dict_list(today_materials)

        today_materials = [MaterialContent(material_id=material["material_id"], page_number=material["page_number"]) for material in today_materials]

        app_logger.info(f"今日的测验的参考材料来源: {today_materials}")
        # 获取今日的材料内容
        today_materials_content = get_material_content(db, today_materials)
        exam.set_prompt(req.num_questions,req.question_types,req.difficulty)
        if today_materials_content:
            abstract_content = abstract.generate_abstract(today_materials_content) # 生成材料的摘要
            app_logger.info(f"材料的摘要: {abstract_content}")
            result = exam.generate_exam(abstract_content)
            return result
        else:
            raise HTTPException(status_code=404, detail=str("今日没有学习的材料"))
    except Exception as e:
        app_logger.error(f"获取今日测验试题失败: {e}")
        raise HTTPException(status_code=500, detail=str("获取今日测验试题失败"))


@router.post("/getConsolidationExam")
def get_consolidation_exam(req: ExamRequest, db: Session = Depends(get_db),current_user: LearnUser = Depends(get_current_user)):
    # 巩固练习
    # 获取最近1～2天内的新知识
    if req.num_questions > 30:
        app_logger.info(f"巩固练习的题目数量大于30！！！")
        raise HTTPException(status_code=400, detail=str("巩固练习的题目数量大于30"))
    recent_knowledge_points = get_all_knowledge_points_by_date_range(db, current_user.id, 0, 2,req.material_id)
    recent_materials = [{"material_id":point.material_id,"page_number":point.page_number} for point in recent_knowledge_points]
    recent_materials = deduplicate_dict_list(recent_materials)
    app_logger.info(f"最近1～2天的材料: {recent_materials}")
    
    # 获取3～7天前的中期知识
    mid_knowledge_points = get_all_knowledge_points_by_date_range(db, current_user.id, 3, 7, req.material_id)
    # 如果知识点数量大于30，则随机抽取30个知识点
    if len(mid_knowledge_points) > 30:
        mid_knowledge_points = random.sample(mid_knowledge_points, 30)
    mid_materials = [{"material_id": point.material_id, "page_number": point.page_number} for point in mid_knowledge_points]
    mid_materials = deduplicate_dict_list(mid_materials)
    app_logger.info(f"3～7天前的材料: {mid_materials}")

    # 获取1～2周前的较早知识
    early_knowledge_points = get_all_knowledge_points_by_date_range(db, current_user.id, 8, 14, req.material_id)
    # 如果知识点数量大于30，则随机抽取30个知识点
    if len(early_knowledge_points) > 30:
        early_knowledge_points = random.sample(early_knowledge_points, 30)
    early_materials = [{"material_id": point.material_id, "page_number": point.page_number} for point in early_knowledge_points]
    early_materials = deduplicate_dict_list(early_materials)
    app_logger.info(f"1～2周前的材料: {early_materials}")

    # 计算每个阶段可用的材料数量
    recent_has_materials = len(recent_materials) > 0
    mid_has_materials = len(mid_materials) > 0
    early_has_materials = len(early_materials) > 0
    
    # 计算有多少个有效时间段
    valid_periods = sum([recent_has_materials, mid_has_materials, early_has_materials])
    
    # 初始分配比例
    recent_ratio = 0.3
    mid_ratio = 0.4
    early_ratio = 0.3
    
    # 如果某个时间段没有材料，重新分配比例
    if valid_periods == 0:
        # 无材料可用，无法生成题目
        return {"result": "无学习记录，无法生成巩固练习"}
    elif valid_periods < 3:
        # 重新分配比例
        if not recent_has_materials:
            # 将近期比例平分给其他有材料的时间段
            if mid_has_materials and early_has_materials:
                mid_ratio += recent_ratio / 2
                early_ratio += recent_ratio / 2
            elif mid_has_materials:
                mid_ratio += recent_ratio
            elif early_has_materials:
                early_ratio += recent_ratio
            recent_ratio = 0
        
        if not mid_has_materials:
            # 将中期比例平分给其他有材料的时间段
            if recent_has_materials and early_has_materials:
                recent_ratio += mid_ratio / 2
                early_ratio += mid_ratio / 2
            elif recent_has_materials:
                recent_ratio += mid_ratio
            elif early_has_materials:
                early_ratio += mid_ratio
            mid_ratio = 0
        
        if not early_has_materials:
            # 将早期比例平分给其他有材料的时间段
            if recent_has_materials and mid_has_materials:
                recent_ratio += early_ratio / 2
                mid_ratio += early_ratio / 2
            elif recent_has_materials:
                recent_ratio += early_ratio
            elif mid_has_materials:
                mid_ratio += early_ratio
            early_ratio = 0
    
    # 计算最终每个时间段应生成的题目数量
    total_questions = req.num_questions
    recent_questions = math.floor(total_questions * recent_ratio) if recent_has_materials else 0
    mid_questions = math.floor(total_questions * mid_ratio) if mid_has_materials else 0
    
    # 处理舍入误差，确保总数正好等于req.num_questions
    early_questions = total_questions - recent_questions - mid_questions if early_has_materials else 0
    
    # 如果仍有舍入误差导致总数不等于req.num_questions，将差值加到有材料的时间段
    if recent_questions + mid_questions + early_questions < total_questions and valid_periods > 0:
        remaining = total_questions - (recent_questions + mid_questions + early_questions)
        if recent_has_materials:
            recent_questions += remaining
        elif mid_has_materials:
            mid_questions += remaining
        elif early_has_materials:
            early_questions += remaining
    app_logger.info(f"recent题目数量: {recent_questions}, mid题目数量: {mid_questions}, early题目数量: {early_questions}")
    
    # 生成试题
    recent_result = []
    mid_result = []
    early_result = []
    if recent_questions > 0:
        recent_materials = [MaterialContent(material_id=material["material_id"], page_number=material["page_number"]) for material in recent_materials]
        recent_content = get_material_content(db, recent_materials)
        exam.set_prompt(recent_questions, req.question_types, req.difficulty)
        abstract_content = abstract.generate_abstract(recent_content)
        recent_result = exam.generate_exam(abstract_content)["questions"] if recent_materials else []

    if mid_questions > 0:
        mid_materials = [MaterialContent(material_id=material["material_id"], page_number=material["page_number"]) for material in mid_materials]
        mid_content = get_material_content(db, mid_materials)
        exam.set_prompt(mid_questions, req.question_types, req.difficulty)
        abstract_content = abstract.generate_abstract(mid_content)
        mid_result = exam.generate_exam(abstract_content)["questions"] if mid_materials else []

    if early_questions > 0:
        early_materials = [MaterialContent(material_id=material["material_id"], page_number=material["page_number"]) for material in early_materials]
        early_content = get_material_content(db, early_materials)
        exam.set_prompt(early_questions, req.question_types, req.difficulty)
        abstract_content = abstract.generate_abstract(early_content)
        early_result = exam.generate_exam(abstract_content)["questions"] if early_materials else []

    result = recent_result + mid_result + early_result
    return {"questions": result}
    
   
   
   



